#include "circular_queue.h"

/**
 * @desc  : 初始化队列
 * @date  : 2025-03-26
 * @author: AnRui
 * @param : queue - {参数说明}: 队列
 * @param : buffer - {参数说明}: 队列缓冲区地址
 * @param : size - {参数说明}: 队列缓冲区长度
 * @note  :
 */
QueueStatusEnum QueueInit(QueueStruct* queue, uint8_t* buffer, uint32_t size) {
    if (queue == NULL || buffer == NULL || size == 0) return QUEUE_ERROR;
    queue->buffer = buffer;
    queue->size = size;
    queue->curNum = 0;
    queue->head = 0;
    queue->tail = 0;
    return QUEUE_OK;
}

/**
 * @desc  : 向队列中压入数据
 * @date  : 2025-03-26
 * @author: AnRui
 * @param : queue - {参数说明}: 队列指针
 * @param : data - {参数说明}: 待压入的数据
 * @return: 队列的操作状态码
 * @note  :
 */
QueueStatusEnum QueuePush(QueueStruct* queue, uint8_t data) {
    if (queue == NULL) return QUEUE_ERROR;
    // 检测是否已满
    if (queue->curNum == queue->size) return QUEUE_OVERLOAD;
    // 把数据放到数组中
    queue->buffer[queue->tail] = data;
    // 更新tail
    queue->tail = (queue->tail + 1) % queue->size;
    // 更新当前数量
    queue->curNum++;
    return QUEUE_OK;
}

/**
 * @desc  : 从队列中弹出数据
 * @date  : 2025-03-26
 * @author: AnRui
 * @param : queue - {参数说明}: 队列指针
 * @param : data - {参数说明}:  数据指针
 * @return: 队列的操作状态码
 * @note  :
 */
QueueStatusEnum QueuePop(QueueStruct* queue, uint8_t* data) {
    if (queue == NULL || data == NULL) return QUEUE_ERROR;
    // 判断是否为空
    if (queue->curNum == 0) return QUEUE_EMPTY;
    // 把数据放到指针位置    
    *data = queue->buffer[queue->head];
    // 更新head
    queue->head = (queue->head + 1) % queue->size;
    // 更新当前数量
    queue->curNum--;
    return QUEUE_OK;
}



/**
 * @desc  : 向队列中压入一组数据
 * @date  : 2025-03-26
 * @author: AnRui
 * @param : queue - {参数说明}: 队列指针
 * @param : dataArr - {参数说明}: 要压入的数据数组指针
 * @param : len - {参数说明}: 需要压入数据的长度
 * @return: 队列的操作状态码
 * @note  :
 */
QueueStatusEnum QueuePushArr(QueueStruct* queue, uint8_t* dataArr, uint32_t len) {
    if (queue == NULL || dataArr == NULL || len == 0) return QUEUE_ERROR;
    //检测剩余空间是否能够
    if ((queue->curNum + len) > queue->size) return QUEUE_OVERSIZE;
    // tail到达尾部的空间 这个时候不用考虑tail会超过head 这种情况上面的检测就过不了
    uint32_t spaceToEnd = queue->size - queue->tail;
    // 处理尾部空间
    if (len <= spaceToEnd) {
        // 数据可以一次性放入尾部
        memcpy(queue->buffer + queue->tail, dataArr, len);
        queue->tail = (queue->tail + len) % queue->size;
    } else {
        // 数据需要分成两部分
        memcpy(queue->buffer + queue->tail, dataArr, spaceToEnd);
        memcpy(queue->buffer, dataArr + spaceToEnd, len - spaceToEnd);
        queue->tail = len - spaceToEnd;
    }
    queue->curNum += len;
    return QUEUE_OK;
}

/**
 * @desc  : 从队里中弹出一组数组
 * @date  : 2025-03-26
 * @author: AnRui
 * @param : queue - {参数说明}:队列指针
 * @param : dataArr - {参数说明}:待弹出队列的数据缓存地址
 * @param : len - {参数说明}:len, 待弹出队列的数据的最大长度
 * @return: 队列的操作状态码
 * @note  :
 */
QueueStatusEnum QueuePopArr(QueueStruct* queue, uint8_t* dataArr, uint32_t len) {
    if (queue == NULL || dataArr == NULL || len == 0) return QUEUE_ERROR;
    // 检查数据是否足够
    if (queue->curNum < len) return QUEUE_OVERNUM;
    uint32_t dataToEnd = queue->size - queue->head;

    // 处理尾部数据
    if (len <= dataToEnd) {
        // 数据可以一次性从尾部取出
        memcpy(dataArr, queue->buffer + queue->head, len);
        queue->head = (queue->head + len) % queue->size;
    } else {
        // 数据需要分成两部分
        memcpy(dataArr, queue->buffer + queue->head, dataToEnd);
        memcpy(dataArr + dataToEnd, queue->buffer, len - dataToEnd);
        queue->head = len - dataToEnd;
    }
    queue->curNum -= len;
    return QUEUE_OK;
}

/**
 * @desc  : 清空队列
 * @date  : 2025-06-20
 * @author: AnRui
 * @param : queue - {参数说明}: 队列指针
 * @note  :
 */
QueueStatusEnum QueueClear(QueueStruct* queue) {
    if (queue == NULL) return QUEUE_ERROR;
    if (queue->curNum == 0) return QUEUE_OK;
    queue->curNum = 0;
    queue->head = 0;
    queue->tail = 0;
    return QUEUE_OK;
}


/**
 * @desc  : 获取队列中有效数据的个数
 * @date  : 2025-03-26
 * @author: AnRui
 * @param : queue - {参数说明}: 队列
 * @return: 队列中数据的个数
 * @note  :
 */
QueueStatusEnum GetQueueDataNum(QueueStruct* queue, uint32_t* num) {
    if (queue == NULL) return QUEUE_ERROR;
    *num = queue->curNum;
    return QUEUE_OK;
}

